<?php

namespace hiduoke\traits;

use app\common\services\table\DataForm;
use app\common\services\table\DataTable;
use Throwable;


/**
 * 后台控制器trait类
 * 已导入到 @see \app\common\controller\Backend 中
 * 若需修改此类方法：请复制方法至对应控制器后进行重写
 */
trait Backend
{
    public $selectFiled = 'name';

    public $recycleFiled = 'name';

    /**
     * 排除入库字段
     * @param array $params
     * @return array
     */
    protected function excludeFields(array $params): array
    {
        if (!is_array($this->preExcludeFields)) {
            $this->preExcludeFields = explode(',', (string)$this->preExcludeFields);
        }

        foreach ($this->preExcludeFields as $field) {
            if (array_key_exists($field, $params)) {
                unset($params[$field]);
            }
        }
        return $params;
    }

    /**
     * 查看
     * @throws Throwable
     */
    public function index()
    {
        if ($this->request->param('select')) {
            return $this->select();
        }
        list($where, $alias, $limit, $order) = $this->queryBuilder();
        $res = $this->model
            ->field($this->indexField)
            ->withJoin($this->withJoinTable, $this->withJoinType)
            ->alias($alias)
            ->where($where)
            ->order($order)
            ->paginate($limit);
        return $this->success('', [
            'list'  => $res->items(),
            'total' => $res->total(),
        ]);
    }

    /**
     * 表格
     * @return \think\response\Json
     */
    public function table()
    {
        $DataTable = (new DataTable($this->model));
        if ($this->request->param('recycle')) {
            // 回收站
            $DataTable->field([$this->model->getPk(), 'delete_time']);
        }
        $column = $DataTable->operation()->create();
        return $this->success('ok', ['column' => $column, 'pk' => $this->model->getPk()]);
    }

    /**
     * 回收站
     * @return \think\response\Json
     * @throws Throwable
     */
    public function recycle()
    {
        if ($this->request->param('select')) {
            $this->select();
        }
        list($where, $alias, $limit, $order) = $this->queryBuilder();
        $res = $this->model
            ->onlyTrashed()
            ->field($this->indexField)
            ->alias($alias)
            ->where($where)
            ->order($order)
            ->paginate($limit);
        return $this->success('', [
            'list'  => $res->items(),
            'total' => $res->total(),
        ]);
    }

    /**
     * 回收站表格
     * @return \think\response\Json
     */
    public function recycleTable()
    {
        $table_column = (new DataTable($this->model))
            ->field([$this->model->getPk(), $this->recycleFiled, 'delete_time'])
            ->create();
        return $this->success('ok', ['column' => $table_column]);
    }

    public function destroy($ids = null)
    {
        if (false === $this->request->isPost()) {
            return $this->error('参数错误');
        }
        $ids = $ids ?: $this->request->post('ids');
        $pk = $this->model->getPk();
        $count = 0;
        $this->model->startTrans();
        try {
            if ($ids) {
                $list = $this->model->onlyTrashed()->where($pk, 'in', $ids)->select();
            } else {
                $list = $this->model->onlyTrashed()->select();
            }
            foreach ($list as $item) {
                $count += $item->force()->delete();
            }
            $this->model->commit();
        } catch (Throwable $e) {
            $this->model->rollback();
            return $this->error($e->getMessage());
        }
        if ($count) {
            return $this->success("销毁成功", [$count, $list, $ids]);
        } else {
            return $this->error("未销毁数据");
        }
    }

    public function restore($ids = null)
    {
        if (false === $this->request->isPost()) {
            return $this->error('参数错误');
        }
        $ids = $ids ?: $this->request->post('ids');
        $pk = $this->model->getPk();
        $count = 0;
        $this->model->startTrans();
        try {
            if ($ids) {
                $list = $this->model->onlyTrashed()->where($pk, 'in', $ids)->select();
            } else {
                $list = $this->model->onlyTrashed()->select();
            }
            foreach ($list as $item) {
                $count += $item->restore();
            }
            $this->model->commit();
        } catch (Throwable $e) {
            $this->model->rollback();
            return $this->error($e->getMessage());
        }
        if ($count) {
            return $this->success("还原成功", [$count, $list, $ids]);
        } else {
            return $this->error("未还原数据");
        }
    }

    /**
     * 获取表单
     * @param $id
     * @return \think\response\Json
     * @throws \FormBuilder\Exception\FormBuilderException
     */
    public function form()
    {
        $dataForm = new DataForm($this->model);
        $form = $dataForm->create();
        return $this->success('', $form);
    }

    /**
     * 保存
     * @return \think\response\Json
     */
    public function save()
    {
        $id = input('id', 0);
        $row = $this->model->findOrEmpty($id);
        $formData = getFormData();
        $row->save($formData);
        return $this->success('保存成功');
    }

    /**
     * 编辑
     * @throws Throwable
     */
    public function edit()
    {
        $id = $this->request->param($this->model->getPk());
        $row = $this->model->find($id);
        if (!$row) {
            $this->error('未找到记录');
        }
        if ($this->request->isPost()) {
            $data = $this->request->post();
            if (!$data) {
                $this->error("参数不能为空", ['']);
            }

            $data = $this->excludeFields($data);
            $this->model->startTrans();
            try {
                // 模型验证
                if ($this->modelValidate) {
                    $validate = str_replace("\\model\\", "\\validate\\", get_class($this->model));
                    if (class_exists($validate)) {
                        $validate = new $validate;
                        if ($this->modelSceneValidate) $validate->scene('edit');
                        $validate->check($data);
                    }
                }
                $result = $row->save($data);
                $this->model->commit();
            } catch (Throwable $e) {
                $this->model->rollback();
                return $this->error($e->getMessage());
            }
            if ($result !== false) {
                $this->success('更新成功');
            } else {
                $this->error('未更新任何行');
            }
        }

        return $this->success('更新成功', [
            'row' => $row
        ]);
    }

    /**
     * 删除
     * @param array $ids
     * @throws Throwable
     */
    public function del(array $ids = [])
    {
        if (!$this->request->isDelete() || !$ids) {
            return $this->error('参数错误');
        }

        $where = [];
        $pk = $this->model->getPk();
        $where[] = [$pk, 'in', $ids];
        $count = 0;
        $data = $this->model->where($where)->select();
        $this->model->startTrans();
        try {
            foreach ($data as $v) {
                $count += $v->delete();
            }
            $this->model->commit();
        } catch (Throwable $e) {
            $this->model->rollback();
            return $this->error($e->getMessage());
        }
        if ($count) {
            return $this->success('删除成功');
        } else {
            return $this->error('未删除任何行');
        }
    }

    /**
     * 排序
     * @param int $id 排序主键值
     * @param int $targetId 排序位置主键值
     * @throws Throwable
     */
    public function sortable(int $id, int $targetId)
    {
        $row = $this->model->find($id);
        $target = $this->model->find($targetId);

        if (!$row || !$target) {
            return $this->error('未找到记录');
        }
        if ($row[$this->weighField] == $target[$this->weighField]) {
            $autoSortEqWeight = is_null($this->autoSortEqWeight) ? false : $this->autoSortEqWeight;
            if (!$autoSortEqWeight) {
                return $this->error('排序规则无效，因为两个目标的权重相等，或者无排序字段', [$row[$this->weighField], $target[$this->weighField]]);
            }
            // 自动重新整理排序
            $all = $this->model->select();
            foreach ($all as $item) {
                $item[$this->weighField] = $item[$this->model->getPk()];
                $item->save();
            }
            unset($all);
            // 重新获取
            $row = $this->model->find($id);
            $target = $this->model->find($targetId);
        }

        $backup = $target[$this->weighField];
        $target[$this->weighField] = $row[$this->weighField];
        $row[$this->weighField] = $backup;
        $row->save();
        $target->save();

        $this->success();
        return $this->success('排序成功');
    }

    /**
     * 加载为select(远程下拉选择框)数据，默认还是走$this->index()方法
     * 必要时请在对应控制器类中重写
     */
    public function select()
    {
        $select = [];
        $where = [];
        $query = $this->request->param('query');
        $filed = $this->request->param('label', $this->selectFiled);
        $val = $this->request->param('val', $this->model->getPk());
        if ($query) {
            $where[] = [$filed, "LIKE", "%" . $query . "%"];
        }
        $row = $this->model->where($where)->select();
        foreach ($row as $key => $value) {
            $select[] = [
                'label' => isset($value[$filed]) && $value[$filed] ? $value[$filed] : "未命名(" . $value[$val].')',
                'value' => $value[$val]
            ];
        }
        return $this->success('', $select);
    }
}
